﻿<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>加密算法---BCryptPasswordEncoder的使用及原理</title>
  <link rel="stylesheet" href="https://stackedit.io/style.css" />
</head>

<body class="stackedit">
  <div class="stackedit__html"><h2><a id="__0"></a>一 介绍</h2>
<p>spring security中的BCryptPasswordEncoder方法采用SHA-256 +随机盐+密钥对密码进行加密。SHA系列是Hash算法，不是加密算法，使用加密算法意味着可以解密（这个与编码/解码一样），但是采用Hash处理，其过程是不可逆的。</p>
<p>1）加密(encode)：注册用户时，使用SHA-256+随机盐+密钥把用户输入的密码进行hash处理，得到密码的hash值，然后将其存入数据库中。</p>
<p>（2）密码匹配(matches)：用户登录时，密码匹配阶段并没有进行密码解密（因为密码经过Hash处理，是不可逆的），而是使用相同的算法把用户输入的密码进行hash处理，得到密码的hash值，然后将其与从数据库中查询到的密码hash值进行比较。如果两者相同，说明用户输入的密码正确。</p>
<h2><a id="__8"></a>二 案例使用</h2>
<h3><a id="21__10"></a>2.1 添加依赖</h3>
<pre><code class="prism language-xml">      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.security<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
            <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-security-core<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
             <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>5.7.6<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
</code></pre>
<h2><a id="22_PasswordConfig_20"></a>2.2 PasswordConfig</h2>
<p>为了防止有人能根据密文推测出salt，我们需要在使用BCryptPasswordEncoder时配置随即密钥，创建一个PasswordConfig配置类，注册BCryptPasswordEncoder对象：</p>
<pre><code class="prism language-java"><span class="token keyword">import</span> <span class="token import"><span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">Data</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>context<span class="token punctuation">.</span>properties<span class="token punctuation">.</span></span><span class="token class-name">ConfigurationProperties</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Bean</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Configuration</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>crypto<span class="token punctuation">.</span>bcrypt<span class="token punctuation">.</span></span><span class="token class-name">BCryptPasswordEncoder</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>security<span class="token punctuation">.</span></span><span class="token class-name">SecureRandom</span></span><span class="token punctuation">;</span>
<span class="token annotation punctuation">@Data</span>
<span class="token annotation punctuation">@Configuration</span>
<span class="token annotation punctuation">@ConfigurationProperties</span><span class="token punctuation">(</span>prefix <span class="token operator">=</span> <span class="token string">"encoder.crypt"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PasswordConfig</span> <span class="token punctuation">{</span>
    <span class="token comment">/**
     * 加密强度
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> strength<span class="token punctuation">;</span>
    <span class="token comment">/**
     * 干扰因子
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> secret<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> <span class="token class-name">BCryptPasswordEncoder</span> <span class="token function">passwordEncoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">//System.out.println("secret = " + secret);</span>
        <span class="token comment">//对干扰因子加密</span>
        <span class="token class-name">SecureRandom</span> secureRandom <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SecureRandom</span><span class="token punctuation">(</span>secret<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//对密码加密</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">BCryptPasswordEncoder</span><span class="token punctuation">(</span>strength<span class="token punctuation">,</span> secureRandom<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

</code></pre>
<h3><a id="23_applicationyml_55"></a>2.3 application.yml</h3>
<pre><code class="prism language-yml"><span class="token key atrule">encoder</span><span class="token punctuation">:</span>
  <span class="token key atrule">crypt</span><span class="token punctuation">:</span>
    <span class="token key atrule">secret</span><span class="token punctuation">:</span> $<span class="token punctuation">{</span>random.uuid<span class="token punctuation">}</span> <span class="token comment"># 随机的密钥，使用uuid</span>
    <span class="token key atrule">strength</span><span class="token punctuation">:</span> <span class="token number">6</span> <span class="token comment"># 加密强度4~31，决定盐加密时的运算强度，超过10以后加密耗时会显著增加</span>
</code></pre>
<h3><a id="24__63"></a>2.4 单元测试</h3>
<pre><code class="prism language-java">
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>junit<span class="token punctuation">.</span>jupiter<span class="token punctuation">.</span>api<span class="token punctuation">.</span></span><span class="token class-name">Test</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Autowired</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>test<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">SpringBootTest</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>crypto<span class="token punctuation">.</span>bcrypt<span class="token punctuation">.</span></span><span class="token class-name">BCryptPasswordEncoder</span></span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@SpringBootTest</span>
<span class="token keyword">class</span> <span class="token class-name">ApplicationTests</span> <span class="token punctuation">{</span>
    <span class="token keyword">final</span> <span class="token keyword">static</span> <span class="token keyword">private</span> <span class="token class-name">String</span> password <span class="token operator">=</span> <span class="token string">"123456"</span><span class="token punctuation">;</span>
    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">BCryptPasswordEncoder</span> encoder<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Test</span>
    <span class="token keyword">void</span> <span class="token function">savePassword</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// encode()：对明文字符串进行加密</span>
        <span class="token comment">//注册用户时，使用SHA-256+随机盐+密钥把用户输入的密码进行hash处理，得到密码的hash值，然后将其存入数据库中。</span>
        <span class="token class-name">String</span> encode1 <span class="token operator">=</span> encoder<span class="token punctuation">.</span><span class="token function">encode</span><span class="token punctuation">(</span>password<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"encode1:"</span> <span class="token operator">+</span> encode1<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> encode2 <span class="token operator">=</span> encoder<span class="token punctuation">.</span><span class="token function">encode</span><span class="token punctuation">(</span>password<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"encode2:"</span> <span class="token operator">+</span> encode2<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// matches()：对加密前和加密后是否匹配进行验证</span>
        <span class="token comment">//用户登录时，密码匹配阶段并没有进行密码解密（因为密码经过Hash处理，是不可逆的），</span>
        <span class="token comment">// 而是使用相同的算法把用户输入的密码进行hash处理，得到密码的hash值，然后将其与从数据库中查询到的密码hash值进行比较。</span>
        <span class="token comment">// 如果两者相同，说明用户输入的密码正确。</span>
        <span class="token keyword">boolean</span> matches1 <span class="token operator">=</span> encoder<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span>password<span class="token punctuation">,</span> encode1<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"matches1:"</span> <span class="token operator">+</span> matches1<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">boolean</span> matches2 <span class="token operator">=</span> encoder<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span>password<span class="token punctuation">,</span> encode2<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"matches2:"</span> <span class="token operator">+</span> matches2<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

</code></pre>
<h3><a id="25__100"></a>2.5 结果</h3>
<p><img src="https://img-blog.csdnimg.cn/fad39f6e2f2d4cadb02e052d66cfa936.png" alt="在这里插入图片描述"></p>
<p><a href="https://blog.csdn.net/weixin_43453386/article/details/123716830">SpringSecurity中的BCryptPasswordEncoder算法</a><br>
<a href="https://blog.csdn.net/u012888704/article/details/107406374">SpringSecurity中的密码加密算法：BCryptPasswordEncoder</a><br>
<a href="https://cloud.tencent.com/developer/article/1779217">BCryptPasswordEncoder使用</a></p>
</div>
</body>

</html>
